﻿
using HBase;
using System;
using System.Collections.Generic;
namespace hCommand {


    public class ComplexPosLineMoveD2 {

        /**
         * 所有的x，y 都是相对于1号 位置
         * 
         */

        Point offsetPoint;
        int yRunTime = 3;
        //同一个取货点，2号位置比1号位置在x方向上多行走的指标，正数时编号方向与x方向一致
        public ComplexPosLineMoveD2(int secondSeaterDistanceX ,int secondSeaterDistanceY = 0 ,int yRunTime = 3) {
            offsetPoint = new Point(secondSeaterDistanceX ,secondSeaterDistanceY);
            this.yRunTime = yRunTime;
        }


        /**
         * 从多个中取两个的逻辑，仅在垛机货叉都为空闲的时候使用
         * */
        public List<TaskOrder> pick2(int x ,int y ,List<LineMove> fullTaskList) {
            Point current = new Point(x ,y);
            int count = fullTaskList.Count;
            if( fullTaskList.Count == 1 ) {
                List<TaskOrder> order1 = onlyOne(current ,fullTaskList[0] ,1);
                List<TaskOrder> order2 = onlyOne(current ,fullTaskList[0] ,2);
                return min(order1 ,order2);
            }
            List<TaskOrder> minOrder = null;
            for( int i = 0;i < count;i++ ) {
                LineMove ft1 = fullTaskList[i];
                List<TaskOrder> order = fromTask(current ,ft1 ,fullTaskList);
                minOrder = min(minOrder ,order);
            }
            return minOrder;
        }
        public List<TaskOrder> pickedOne(int x ,int y ,LineMove ft ,List<LineMove> fullTaskList ,int forkNo) {
            Point current = new Point(x ,y);
            return pick(current ,ft ,fullTaskList ,forkNo);
        }

        public List<TaskOrder> put2minTime(int x ,int y ,LineMove ft1 ,LineMove ft2) {
            Point current = new Point(x ,y);
            return put2minTime(current ,ft1 ,ft2);
        }

        private int time(Point current ,Point to ,int forkNO) {
            double vx = to.X - current.X - offsetPoint.X * (forkNO - 1);
            double vy = to.Y - current.Y - offsetPoint.Y * (forkNO - 1);
            double tx = Math.Abs(vx);
            double ty = Math.Abs(vy) * yRunTime;
            return ( int ) Math.Max(tx ,ty);
        }
        /**
         * 仅一个任务时
         * */
        private List<TaskOrder> onlyOne(Point current ,LineMove ft ,int forkNO) {
            if( ft.refuse(forkNO) ) {
                return null;
            }

            List<TaskOrder> res = new List<TaskOrder>();
            int t1 = time(current ,ft.getS() ,forkNO);
            res.Add(new TaskOrder(t1 ,ft ,forkNO ,CraneStep.pick));

            current = getBasePoint(ft.getS() ,forkNO);
            int t2 = time(current ,ft.getD() ,forkNO);
            res.Add(new TaskOrder(t2 ,ft ,forkNO ,CraneStep.put));
            return res;
        }
        private List<TaskOrder> fromTask(Point current ,LineMove ft1 ,List<LineMove> fullTaskList) {
            List<TaskOrder> order1 = pick(current ,ft1 ,fullTaskList ,1);
            List<TaskOrder> order2 = pick(current ,ft1 ,fullTaskList ,2);
            return min(order1 ,order2);
        }
        /**
         *  x 垛机上显示的x轴位置
         * 
         * */
        private List<TaskOrder> pick(Point current ,LineMove ft ,List<LineMove> fullTaskList ,int forkNo) {
            if( ft.refuse(forkNo) ) {
                return null;
            }
            List<TaskOrder> res = new List<TaskOrder>();
            int pickTime = time(current ,ft.getS() ,forkNo);
            res.Add(new TaskOrder(pickTime ,ft ,forkNo ,CraneStep.pick));


            List<TaskOrder> order1Next1 = pickFirstFinsh(ft ,forkNo ,fullTaskList);
            res.AddRange(order1Next1);
            return res;
        }
        private List<TaskOrder> pickFirstFinsh(LineMove ft1 ,int forkNo ,List<LineMove> fullTaskList) {
            Point current = getBasePoint(ft1.getS() ,forkNo);
            List<TaskOrder> minOrder = null;
            foreach( LineMove ft in fullTaskList ) {
                if( ft == ft1 ) {//同一个对象
                    continue;
                }
                List<TaskOrder> pickRorder = pickTegether(current ,ft1 ,forkNo ,ft);
                minOrder = min(minOrder ,pickRorder);
                pickRorder = oneByOne(current ,ft1 ,forkNo ,ft);
                minOrder = min(minOrder ,pickRorder);
            }
            return minOrder;
        }
        private List<TaskOrder> pickTegether(Point current ,LineMove ft1 ,int forkNo ,LineMove otherFt) {//取两个货的时间
            List<TaskOrder> res = new List<TaskOrder>();
            int otherForkNO = 3 - forkNo;
            if( otherFt.refuse(otherForkNO) ) {
                int pickOnlyTime = time(current ,ft1.getD() ,forkNo);
                res.Add(new TaskOrder(pickOnlyTime ,ft1 ,forkNo ,CraneStep.put));
                return res;
            }


            int pickTime = time(current ,otherFt.getS() ,otherForkNO);
            res.Add(new TaskOrder(pickTime ,otherFt ,otherForkNO ,CraneStep.pick));
            Point putBegin = getBasePoint(otherFt.getS() ,otherForkNO);

            if( forkNo == 1 ) {
                res.AddRange(put2minTime(putBegin ,ft1 ,otherFt));
            } else {
                res.AddRange(put2minTime(putBegin ,otherFt ,ft1));

            }
            return res;
        }
        private List<TaskOrder> oneByOne(Point current ,LineMove ft1 ,int forkNo ,LineMove ft) {
            List<TaskOrder> res = new List<TaskOrder>();
            int putTime = time(current ,ft1.getD() ,forkNo);
            res.Add(new TaskOrder(putTime ,ft1 ,forkNo ,CraneStep.put));
            int otherFork = 3 - forkNo;
            if( !ft.refuse(otherFork) ) {
                current = getBasePoint(ft1.getD() ,forkNo);
                int nextPickTime = time(current ,ft.getS() ,otherFork);

                res.Add(new TaskOrder(nextPickTime ,ft ,otherFork ,CraneStep.pick));
                current = getBasePoint(ft.getS() ,otherFork);

                int nextPutTime = time(current ,ft.getD() ,otherFork);
                res.Add(new TaskOrder(nextPutTime ,ft ,otherFork ,CraneStep.put));
            }
            return res;
        }
        private List<TaskOrder> put2minTime(Point current ,LineMove ft1 ,LineMove ft2) {//放两个货的时间
            List<TaskOrder> res = new List<TaskOrder>();

            int t11 = time(current ,ft1.getD() ,1);
            int t12 = time(ft1.getD() ,ft2.getD() ,2);

            int t21 = time(current ,ft2.getD() ,2);
            Point current1 = getBasePoint(ft2.getD() ,2);
            int t22 = time(current1 ,ft1.getD() ,1);
            if( t11 + t12 < t21 + t22 ) {
                res.Add(new TaskOrder(t11 ,ft1 ,1 ,CraneStep.put));
                res.Add(new TaskOrder(t12 ,ft2 ,2 ,CraneStep.put));
            } else {
                res.Add(new TaskOrder(t21 ,ft2 ,2 ,CraneStep.put));
                res.Add(new TaskOrder(t22 ,ft1 ,1 ,CraneStep.put));
            }
            return res;
        }

        private Point getBasePoint(Point current ,int forkNo) {
            double x = current.X - offsetPoint.X * (forkNo - 1);
            double y = current.Y - offsetPoint.Y * (forkNo - 1);
            return new Point(x ,y);
        }


        private List<TaskOrder> min(List<TaskOrder> minOrder ,List<TaskOrder> order1) {
            if( minOrder == null ) {
                return order1;
            }
            if( order1 == null ) {
                return minOrder;
            }
            if( minOrder.Count > order1.Count ) {
                return minOrder;


            } else if( minOrder.Count < order1.Count ) {

                return order1;
            } else {
                long t1 = 0;
                foreach( TaskOrder o in minOrder ) {
                    t1 += o.time;
                }
                long t2 = 0;
                foreach( TaskOrder o in order1 ) {
                    t2 += o.time;
                }
                if( t1 > t2 ) {
                    return order1;
                }
                return minOrder;
            }
        }
    }



    public enum CraneStep {
        none = 0, pick = 1, put = 2
    }
    public class TaskOrder {
        public CraneStep step = 0;
        public long time = 0;

        public LineMove tc1;
        public byte forkNo;
        public TaskOrder(int t ,LineMove tc ,int forkNo ,CraneStep step) {

            time = t;
            tc1 = tc;
            this.forkNo = ( byte ) forkNo;
            this.step = step;
        }
    }
}
